package com.gigi.searchcenterbackendmaster.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gigi.searchcenterbackendmaster.mapper.ArticleMapper;
import com.gigi.searchcenterbackendmaster.model.dto.ArticleEsDTO;
import com.gigi.searchcenterbackendmaster.model.entity.ArticleEntity;
import com.gigi.searchcenterbackendmaster.model.enums.ErrorCodeEnum;
import com.gigi.searchcenterbackendmaster.model.request.SearchSuggestRequest;
import com.gigi.searchcenterbackendmaster.model.vo.ArticleVO;
import com.gigi.searchcenterbackendmaster.service.ArticleService;
import com.gigi.searchcenterbackendmaster.util.ThrowUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.suggest.response.Suggest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 文章表 服务实现类
 * </p>
 *
 * @author Gigi
 * @since 2024-08-17
 */
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, ArticleEntity> implements ArticleService {

    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public List<ArticleVO> searchFromEs(String keyword) {

        // 1、构造查询条件

        // 按关键词检索
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (StrUtil.isNotBlank(keyword)) {
            boolQueryBuilder.should(QueryBuilders.matchQuery("title", keyword));
            boolQueryBuilder.should(QueryBuilders.matchQuery("zhaiyao", keyword));
            boolQueryBuilder.minimumShouldMatch(1);
        }

        // 过滤出未删除的
        boolQueryBuilder.filter(QueryBuilders.termQuery("ifDelete", 0));

        // 高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder()
                .field("zhaiyao")
                .field("title")
                .preTags("<span style=\"color: red\">")
                .postTags("</span>");

        // 按分数、创建时间降序排序
        SortBuilder<?> sortByScore = SortBuilders.scoreSort();
        SortBuilder<?> sortByCreateTime = SortBuilders.fieldSort("createTime").order(SortOrder.DESC);

        // 组合查询条件
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .withSorts(sortByScore, sortByCreateTime)
                .withHighlightBuilder(highlightBuilder)
                .build();

        // 2、调用 ElasticsearchRestTemplate 进行查询
        SearchHits<ArticleEsDTO> searchHits = elasticsearchRestTemplate.search(searchQuery, ArticleEsDTO.class);

        //（3、如果需要其他动态字段，根据 id 反查 mysql）

        // 4、封装返回
        if (!searchHits.hasSearchHits()) {
            return Collections.emptyList();
        }
        return searchHits.getSearchHits().stream().map(item -> {
            ArticleVO articleVO = new ArticleVO();
            List<String> highlightTitle = item.getHighlightField("title");
            List<String> highlightZhaiyao = item.getHighlightField("zhaiyao");
            articleVO.setTitle(CollUtil.isNotEmpty(highlightTitle) ? highlightTitle.get(0) : item.getContent().getTitle());
            articleVO.setZhaiyao(CollUtil.isNotEmpty(highlightZhaiyao) ? highlightZhaiyao.get(0) : item.getContent().getZhaiyao());
            articleVO.setCreateTime(DateUtil.formatDateTime(item.getContent().getCreateTime()));
            return articleVO;
        }).collect(Collectors.toList());
    }

    @Override
    public List<String> suggest(SearchSuggestRequest request) {
        ThrowUtil.throwIf(StrUtil.isBlank(request.getKeyword()), ErrorCodeEnum.PARAMS_ERROR);

        // 1、构建查询建议
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        suggestBuilder.addSuggestion("my-suggestion",
                SuggestBuilders.completionSuggestion("suggest")
                        .prefix(request.getKeyword())
                        .size(10)
        );

        // 2、组合查询条件
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withSuggestBuilder(suggestBuilder)
                .build();

        // 2、调用 ElasticsearchRestTemplate 进行查询
        SearchHits<ArticleEsDTO> searchHits = elasticsearchRestTemplate.search(searchQuery, ArticleEsDTO.class);

        // 3、解析结果
        if (!searchHits.hasSuggest()) {
            return Collections.emptyList();
        }
        List<? extends Suggest.Suggestion.Entry.Option> options =
                searchHits.getSuggest().getSuggestion("my-suggestion").getEntries().get(0).getOptions();
        return options.stream().map(item -> {
            return item.getText().toString();
        }).collect(Collectors.toList());
    }

}
